package com.linsen.core.rabbitmq.config;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.linsen.core.common.annotation.AutoConfiguration;
import com.linsen.core.rabbitmq.constant.DelayedConstant;
import com.linsen.core.rabbitmq.exchange.DelayedExchange;
import com.linsen.core.rabbitmq.props.LinsenRabbitMQProperties;
import com.linsen.core.rabbitmq.service.RabbitMQService;
import lombok.RequiredArgsConstructor;
import org.springframework.amqp.core.AcknowledgeMode;
import org.springframework.amqp.rabbit.annotation.EnableRabbit;
import org.springframework.amqp.rabbit.annotation.RabbitListenerConfigurer;
import org.springframework.amqp.rabbit.config.SimpleRabbitListenerContainerFactory;
import org.springframework.amqp.rabbit.connection.CachingConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.rabbit.listener.RabbitListenerEndpointRegistrar;
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.messaging.converter.MappingJackson2MessageConverter;
import org.springframework.messaging.handler.annotation.support.DefaultMessageHandlerMethodFactory;

/**
 * RabbitMQ基础配置
 *
 * @author zhaoyong
 * @date 2023/3/13
 */
@EnableRabbit
@AutoConfiguration
@RequiredArgsConstructor
@EnableConfigurationProperties({LinsenRabbitMQProperties.class})
public class LinsenRabbitMQAutoConfiguration implements RabbitListenerConfigurer {
    private final CachingConnectionFactory cachingConnectionFactory;

    @Override
    public void configureRabbitListeners(RabbitListenerEndpointRegistrar rabbitListenerEndpointRegistrar) {
//        rabbitListenerEndpointRegistrar.setMessageHandlerMethodFactory(defaultMessageHandlerMethodFactory());
    }

    @Bean
    public SimpleRabbitListenerContainerFactory rabbitListenerContainerFactory() {
        SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
        factory.setConnectionFactory(cachingConnectionFactory);
        /**
         * 手动Ack参数说明
         * basicAck(long deliveryTag, boolean multiple)
         * deliveryTag：批量处理的标号，举例：这个队列现在有5条消息要消费，那么这批数据会标号从1-5递增，5的时候就会手动Ack  multiple：是否批量处理
         *
         */
        /**
         * basicNack(long deliveryTag, boolean multiple, boolean requeue)
         * requeue：是否送回队列
         */
        //手动Ack
        factory.setAcknowledgeMode(AcknowledgeMode.MANUAL);
        factory.setConcurrentConsumers(1);
        factory.setMaxConcurrentConsumers(1);
        factory.setPrefetchCount(1);
        Jackson2JsonMessageConverter jackson2JsonMessageConverter = new Jackson2JsonMessageConverter(this.objectMapper());
        factory.setMessageConverter(jackson2JsonMessageConverter);
        return factory;
    }

    @Bean
    public DefaultMessageHandlerMethodFactory defaultMessageHandlerMethodFactory() {
        DefaultMessageHandlerMethodFactory factory = new DefaultMessageHandlerMethodFactory();
        // 消费消息时对消息进行反序列化 需要@Payload注解
        MappingJackson2MessageConverter mappingJackson2MessageConverter = new MappingJackson2MessageConverter();
        mappingJackson2MessageConverter.setObjectMapper(objectMapper());
        factory.setMessageConverter(mappingJackson2MessageConverter);
        return factory;
    }

    @Bean
    public RabbitTemplate rabbitTemplate() {
        RabbitTemplate template = new RabbitTemplate(cachingConnectionFactory);
        // 发送消息时对消息进行序列化
        Jackson2JsonMessageConverter jackson2JsonMessageConverter = new Jackson2JsonMessageConverter(objectMapper());
        template.setMessageConverter(jackson2JsonMessageConverter);
        return template;
    }

    @Bean
    public ObjectMapper objectMapper() {
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
        JavaTimeModule javaTimeModule = new JavaTimeModule();
        objectMapper.registerModule(javaTimeModule);
        return objectMapper;
    }

    /**
     * 死信交换机
     */
    @Bean
    @ConditionalOnProperty(prefix = "linsen.rabbitmq", name = "delayed", havingValue = "true")
    public DelayedExchange delayedExchange() {
        return new DelayedExchange(DelayedConstant.DELAYED_EXCHANGE, true, false, DelayedConstant.DEFAULT_DELAYED_EXCHANGE_ARGUMENTS);
    }

    @Bean
    public RabbitMQService rabbitMQService(RabbitTemplate rabbitTemplate) {
        return new RabbitMQService(rabbitTemplate);
    }
}
